using System;
using System.Collections;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text;
using System.Threading;
using Microsoft.Win32;
using UnityEngine;

namespace Project
{
    /// <summary>
    /// 串口管理器,环境必须为.NetFramework
    /// </summary>
    public class SerialPortManager
    {
        private SerialPort _serialPort;
        private Thread _receiveThread;
        private bool _isRunningReceiveThread = true;
        private byte[] _buffer = new byte[16];
        private List<byte> _receiveBuffer = new List<byte>(16);
        private string EndSign = string.Empty; //结束位标志 无结束位可忽略
        
        private event Action<string> onReceiveData;

        /// <summary>
        /// 释放
        /// </summary>
        public void OnDispose()
        {
            CloseSerialPort();
            _isRunningReceiveThread = false;
            onReceiveData = null;
            _receiveThread = null;
        }

        // //使用示范
        // private void DEMO()
        // {
        //    var portManager = new SerialPortManager();
        //    var coms = portManager.ScanPorts_TryFail();
        //    foreach (var com in coms)
        //    {
        //        Debug.Log($"Exists COM: {com}");
        //    }
        //    portManager.OpenSerialPort("COM5",9600,Parity.None,8,StopBits.One)
        //        .SetEndSign("99") //设置数据结束位标识  无可忽略
        //        .AddLstener(OnReceiveDataCallBack);
        // }
        
        #region 打开串口/关闭串口

        /// <summary>
        /// 打开串口
        /// </summary>
        /// <param name="_portName">端口号</param>
        /// <param name="_baudRate">波特率</param>
        /// <param name="_parity">校验位</param>
        /// <param name="dataBits">数据位</param>
        /// <param name="_stopbits">停止位</param>
        /// <param name="_endSign">结束位标记  无则可忽略</param>
        public SerialPortManager OpenSerialPort(string _portName, int _baudRate, Parity _parity, int dataBits, StopBits _stopbits)
        {
            try
            {
                _serialPort = new SerialPort(_portName, _baudRate, _parity, dataBits, _stopbits); //绑定端口
                _serialPort.Open();
                //使用委托 Unity中不适用
                //sp.DataReceived += DataReceived;
                
                //使用线程
                 _receiveThread = new Thread(new ThreadStart(ReceivedData));
                _receiveThread.Start();

                //调试---------------
                Debug.Log($"绑定端口：  {_portName}");
            }
            catch (Exception ex)
            {
                _serialPort = new SerialPort();
                Debug.Log($"绑定端口失败：{_portName}" + ex);
            }

            return this;
        }

        /// <summary>
        /// 设置结束位标识
        /// </summary>
        /// <param name="endSign">结束位标识字符</param>
        /// <returns></returns>
        public SerialPortManager SetEndSign(string _endSign)
        {
            this.EndSign = _endSign;
            return this;
        }
        
        /// <summary>
        /// 关闭串口
        /// </summary>
        private void CloseSerialPort()
        {
            _serialPort.Close();
        }

        #endregion

        #region 添加/移除监听

        public SerialPortManager AddLstener(Action<string> ReceiveCallBack)
        {
            onReceiveData += ReceiveCallBack;
            return this;
        }

        public void RemoveListener(Action<string> ReceiveCallBack)
        {
            onReceiveData -= ReceiveCallBack;
        }

        public void RemoveAllListener()
        {
            onReceiveData = null;
        }

        #endregion

        #region 扫描端口

        //使用API扫描
        public string[] ScanPorts_API()
        {
            string[] portList = SerialPort.GetPortNames();
            return portList;
        }

        //使用注册表信息扫描
        public string[] ScanPorts_Regedit()
        {
            RegistryKey keyCom = Registry.LocalMachine.OpenSubKey("Hardware\\DeviceMap\\SerialComm");
            string[] SubKeys = keyCom.GetValueNames();
            string[] portList = new string[SubKeys.Length];
            for (int i = 0; i < SubKeys.Length; i++)
            {
                portList[i] = (string)keyCom.GetValue(SubKeys[i]);
            }

            return portList;
        }

        //试错方式扫描
        public string[] ScanPorts_TryFail()
        {
            List<string> tempPost = new List<string>();
            bool mark = false;
            for (int i = 0; i < 10; i++)
            {
                try
                {
                    SerialPort sp = new SerialPort("COM" + (i + 1).ToString());
                    sp.Open();
                    sp.Close();
                    tempPost.Add("COM" + (i + 1).ToString());
                    mark = true;
                }
                catch (System.Exception)
                {
                    continue;
                }
            }

            if (mark)
            {
                string[] portList = tempPost.ToArray();
                return portList;
            }
            else
            {
                return null;
            }
        }

        #endregion

        #region 发送数据

        /// <summary>
        /// 直接发送普通字符串
        /// </summary>
        /// <param name="_info">string数据</param>
        public void SendData(string _info)
        {
            try
            {
                if (_serialPort.IsOpen)
                {
                    _serialPort.WriteLine(_info);
                }
                else
                {
                    _serialPort.Open();
                    _serialPort.WriteLine(_info);
                }
            }
            catch (Exception ex)
            {
                Debug.Log(ex);
            }
        }
        
        /// <summary>
        /// 直接发送字节数组
        /// </summary>
        /// <param name="hexData"></param>
        public void SendHexCommand(byte[] hexData)
        {
            if (_serialPort != null && _serialPort.IsOpen)
            {
                try
                {
                    _serialPort.Write(hexData, 0, hexData.Length);
                    Debug.Log($"发送指令: {BitConverter.ToString(hexData)}");
                }
                catch (System.Exception e)
                {
                    Debug.LogError($"发送失败: {e.Message}");
                }
            }
            else
            {
                Debug.LogWarning("串口未打开");
            }
        }
        
        /// <summary>
        /// 发送16进制字符串
        /// </summary>
        /// <param name="hexString">16进制字符串</param>
        public void SendHexString(string hexString)
        {
            // 移除空格和分隔符
            hexString = hexString.Replace(" ", "").Replace("-", "");
    
            // 确保长度为偶数
            if (hexString.Length % 2 != 0)
            {
                Debug.LogError("16进制字符串长度必须为偶数");
                return;
            }
    
            // 转换为字节数组
            byte[] data = new byte[hexString.Length / 2];
            for (int i = 0; i < data.Length; i++)
            {
                string byteString = hexString.Substring(i * 2, 2);
                data[i] = System.Convert.ToByte(byteString, 16);
            }
    
            SendHexCommand(data);
        }
        
        /// <summary>
        /// 发送带校验位的指令
        /// </summary>
        /// <param name="data"></param>
        public void SendHexCommandWithChecksum(byte[] data)
        {
            byte checksum = CalculateChecksum(data);
            byte[] fullCommand = new byte[data.Length + 1];
            System.Array.Copy(data, 0, fullCommand, 0, data.Length);
            fullCommand[data.Length] = checksum;
    
            SendHexCommand(fullCommand);
        }

        //计算校验和 (简单求和取低8位)
        private byte CalculateChecksum(byte[] data)
        {
            int sum = 0;
            foreach (byte b in data)
            {
                sum += b;
            }
            return (byte)(sum & 0xFF);
        }
        
        #endregion

        #region 接收数据

        /// <summary>
        /// 接收数据 回调函数  Unity中不适用
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        [Obsolete]
        private void DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] ReDatas = new byte[_serialPort.BytesToRead];
            _serialPort.Read(ReDatas, 0, ReDatas.Length); //读取数据
            DataProcessing(ReDatas); //数据处理
        }
        
        /// <summary>
        /// 接收数据 线程 
        /// </summary>
        private void ReceivedData()
        {
            while (_isRunningReceiveThread)
            {
                if (_serialPort.IsOpen)
                {
                    int count = _serialPort.BytesToRead;
                    if (count > 0)
                    {
                        _buffer = new byte[count];
                        _serialPort.Read(_buffer, 0, count);
                        // try
                        // {
                            if (string.IsNullOrEmpty(EndSign))
                            {
                                string dataStr = AnalyzePackage(_buffer);
                                HandlerData(dataStr);
                                Debug.Log($"接收串口数据：{dataStr}");
                            }
                            else
                            {
                                for (int i = 0; i < count; i++)
                                {
                                    var temp = BitConverter.ToString(_buffer, i, 1);
                                    if (temp.Equals(EndSign))
                                    {
                                        string dataStr = AnalyzePackage(_receiveBuffer.ToArray());
                                        //清空缓冲区
                                        _receiveBuffer.Clear();
                                        //处理数据
                                        HandlerData(dataStr);
                                        Debug.Log($"接收串口数据：{dataStr}");
                                    }
                                    else
                                    {
                                        //否则加入数据缓冲区
                                        _receiveBuffer.Add(_buffer[i]);
                                    }
                                }
                            }
                            
                        // }
                        // catch (Exception e)
                        // {
                        //     Debug.Log(e.Message);
                        // }
                    }
                }
                Thread.Sleep(10);
            }

            Debug.Log("线程关闭");
        }

        #endregion

        #region 数据处理
        
        /// <summary>
        /// 解析数据包
        /// </summary>
        /// <param name="bytes">数据包</param>
        /// <returns>数据</returns>
        private string AnalyzePackage(byte[] bytes)
        {
            var temp = BitConverter.ToString(bytes, 0, bytes.Length);
            return temp;
        }

        /// <summary>
        /// 数据处理  Unity中不适用
        /// </summary>
        /// <param name="data">字节数组</param>
        [Obsolete]
        private void DataProcessing(byte[] data)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sb.AppendFormat("{0:x2}", data[i]);
            }

            //Debug.Log(sb.ToString());
            var temp = Encoding.UTF8.GetString(data).Split("\n", StringSplitOptions.RemoveEmptyEntries);
            Debug.Log(temp.Length);
            for (int i = 0; i < temp.Length; i++)
            {
                // Debug.Log(temp[i]);
                //main.receive(temp[i]);
                onReceiveData?.Invoke(temp[i]);
            }
        }
        
        /// <summary>
        /// 数据处理  在子线程中  最好到主线程中处理
        /// </summary>
        /// <param name="data"></param>
        private void HandlerData(string data)
        {
            onReceiveData?.Invoke(data);
        }

        #endregion
    }
}